package org.schhx.session;

import java.lang.reflect.*;
import java.util.List;
import java.util.Map;

/**
 * @author shanchao
 * @date 2021/1/30
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
        this.executor = new SimpleExecutor();
    }

    @Override
    public <T> T getMapper(Class<T> type) {
        Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{type}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String namespace = method.getDeclaringClass().getName();
                String statement = String.format("%s.%s", namespace, method.getName());
                Type genericReturnType = method.getGenericReturnType();

                Object parameter = args != null && args.length > 0 ? args[0] : null;

                MappedStatement mappedStatement = configuration.getMappedStatement(statement);

                if ("select".equals(mappedStatement.getOperateType())) {
                    // 判断是否进行了 泛型类型参数化
                    if (genericReturnType instanceof ParameterizedType) {
                        List<Object> objects = selectList(statement, parameter);
                        return objects;
                    } else {
                        return selectOne(statement, parameter);
                    }
                } else {
                    return update(statement, parameter);
                }


            }
        });
        return (T) proxy;
    }

    @Override
    public <T> T selectOne(String statement) throws Exception {
        return selectOne(statement, null);
    }

    @Override
    public <T> T selectOne(String statement, Object parameter) throws Exception {
        List<T> list = selectList(statement, parameter);
        if (list.size() == 1) {
            return list.get(0);
        } else if (list.size() > 1) {
            throw new RuntimeException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
        } else {
            return null;
        }
    }

    @Override
    public <E> List<E> selectList(String statement) throws Exception {
        return selectList(statement, null);
    }

    @Override
    public <E> List<E> selectList(String statement, Object parameter) throws Exception {
        MappedStatement mappedStatement = configuration.getMappedStatement(statement);
        return executor.query(mappedStatement, parameter);
    }

    @Override
    public int insert(String statement) throws Exception {
        return insert(statement, null);
    }

    @Override
    public int insert(String statement, Object parameter) throws Exception {
        return update(statement, parameter);
    }

    @Override
    public int update(String statement) throws Exception {
        return update(statement, null);
    }

    @Override
    public int update(String statement, Object parameter) throws Exception {
        MappedStatement mappedStatement = configuration.getMappedStatement(statement);
        return executor.update(mappedStatement, parameter);
    }

    @Override
    public int delete(String statement) throws Exception {
        return delete(statement, null);
    }

    @Override
    public int delete(String statement, Object parameter) throws Exception {
        return update(statement, parameter);
    }
}
